﻿using System;
using System.Runtime.InteropServices;

namespace Ast.Core
{
    public static class IoCtl
    {
        private static UInt32 CtlCode(UInt32 deviceType, UInt32 function, UInt32 method, UInt32 access)
        {
            return (((deviceType) << 16) | ((access) << 14) | ((function) << 2) | (method));
        }

        public const UInt32 MemTag = 0x888;

        private const UInt32 FileDeviceAst = 0x8000;
        private const UInt32 IoControlBase = 0x800;
        private const UInt32 MethodBuffered = 0;
        private const UInt32 FileAnyAccess = 0;

        public static readonly UInt32 IoCtlKeyboard = CtlCode(FileDeviceAst, IoControlBase + 0, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlMouse = CtlCode(FileDeviceAst, IoControlBase + 1, MethodBuffered, FileAnyAccess);

        public static readonly UInt32 IoCtlGetKpcrAdr = CtlCode(FileDeviceAst, IoControlBase + 10, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlReadMemory = CtlCode(FileDeviceAst, IoControlBase + 100, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlWriteMemory = CtlCode(FileDeviceAst, IoControlBase + 150, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlInvokeFunction = CtlCode(FileDeviceAst, IoControlBase + 200, MethodBuffered, FileAnyAccess);

        public static readonly UInt32 IoCtlNetworkGetProtocolHeader = CtlCode(FileDeviceAst, IoControlBase + 1000, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlNetworkNdisHook = CtlCode(FileDeviceAst, IoControlBase + 1001, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlNetworkGetNetworkPacket = CtlCode(FileDeviceAst, IoControlBase + 1002, MethodBuffered, FileAnyAccess);

        public static readonly UInt32 IoCtlHooKInstall = CtlCode(FileDeviceAst, IoControlBase + 2000, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlHookUninstall = CtlCode(FileDeviceAst, IoControlBase + 2001, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlHookSetMonitorItem = CtlCode(FileDeviceAst, IoControlBase + 2002, MethodBuffered, FileAnyAccess);
        public static readonly UInt32 IoCtlHookGetMonitorInfo = CtlCode(FileDeviceAst, IoControlBase + 2003, MethodBuffered, FileAnyAccess);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct ReadMemoryRequest
        {
            public IntPtr Address;

            public int Length;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct WriteMemoryRequest
        {
            public IntPtr Address;

            public int Length;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct InvokeFunctionRequest
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string FunctionName;

            public int ParamCount;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public IntPtr[] Params;

            public int ReturnZise;

            public bool IsReturnValueType;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct HookSetMonitorItemRequest
        {
            public uint ServiceTableBase;
            public int FunctionIndex;
            public uint ReloadedFunctionAddress;
            public bool IsMonitor;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct NdisHookRequest
        {
            public IntPtr NdisProtocolHandle;
            public IntPtr NdisMiniportHandle;
            public IntPtr SendFuncAddress; // original send function
            public IntPtr RecvFuncAddress; // original recv function
            public IntPtr HookSendAddress;
            public IntPtr HookRecvAddress;
            public bool IsInstall;
        }
    }
}